{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Effects;

interface

uses Classes, Bitmaps, Colours, UIObjects, XMLHelper;

const
  DEFAULT_SCALE = 1.0;

{$IFDEF DESIGNER}
  // Property categories and hints for designer
  CAT_EFFECT = 'Effect';
  HINT_GAMMA = 'specifies the name of a colour item to use for gamma correction';
  HINT_BITMAP = 'specifies the name of a bitmap item to use as an overlay effect';
  HINT_SCALE = 'specifies a combined vertical and horizontal scaling factor';
  HINT_XSCALE = 'specfies a horizontal scaling factor. (Use 1.0 for original size)';
  HINT_YSCALE = 'specfies a vertical scaling factor. (Use 1.0 for original size)';
{$ENDIF}

type
  TAHMEffect = class(TAHMUIObject)
  private
    FBitmap: TAHMBitmap;
    FGamma: TAHMColour;
    FXScale: Single;
    FYScale: Single;
  protected
    function GetScale: Single;
    procedure SetScale(Scale: Single);
    procedure SetXScale(XScale: Single);
    procedure SetYScale(YScale: Single);
    procedure SetGamma(Gamma: TAHMColour);
    procedure ClearProperties; override;
  public
    constructor Create(const Name: String); override;
    function RenderPreview: Boolean; override;
    procedure Assign(Source: TPersistent); override;
    procedure SaveXMLBody(Lines: TStrings); override;
    procedure ParseFromXML(XML: TAHMXMLHelper); override;
    procedure InvalidateUIObject(UIObject: TAHMUIObject); override;
    procedure BuildProperties(Properties: TAHMUIPropertyList); override;
  published
    property Scale: Single read GetScale write SetScale;
    property XScale: Single read FXScale write SetXScale;
    property YScale: Single read FYScale write SetYScale;
    property Bitmap: TAHMBitmap read FBitmap write FBitmap;
    property Gamma: TAHMColour read FGamma write SetGamma;
  end;

  TAHMEffectList = class(TAHMUIObjectList)
  private
  protected
  public
    constructor Create; override;
    function AddEffect(const InheritFrom, NewName: String): TAHMEffect;
    function GetEffect(const Name: String): TAHMEffect;
  end;


implementation

uses SysUtils, ApplicationManager, Screen, Canvas, Colour, BaseControls,
     TagNames, XMLTags, AHMTypes;

constructor TAHMEffectList.Create;
begin
  inherited Create;

  XMLTagName := TAG_EFFECTS;
  ChildClass := TAHMEffect;
end;

function TAHMEffectList.AddEffect(const InheritFrom, NewName: String): TAHMEffect;
begin
  Result := TAHMEffect(Inherit(InheritFrom, NewName));
end;

function TAHMEffectList.GetEffect(const Name: String): TAHMEffect;
begin
  Result := TAHMEffect(GetObject(Name));
end;

//----------------------------------------------------------------------------//
constructor TAHMEffect.Create(const Name: String);
begin
  inherited Create(Name);

  XMLTagName := TAG_EFFECT;
  ObjectType := otEffects;
  ImageIndex := Ord(otEffects);

  // Set default effect properties
  ClearProperties;
end;

function TAHMEffect.GetScale: Single;
begin
  // Return average of X/Y scales
  Result := (FXScale + FYScale) / 2;
end;

procedure TAHMEffect.SetScale(Scale: Single);
begin
  // Set both X & Y scales to same scale
  FXScale := Scale;
  FYScale := Scale;
  ApplicationManagerInstance.UIManager.InvalidateUIObject(Self);
end;

procedure TAHMEffect.SetXScale(XScale: Single);
begin
  FXScale := XScale;
  ApplicationManagerInstance.UIManager.InvalidateUIObject(Self);
end;

procedure TAHMEffect.SetYScale(YScale: Single);
begin
  FYScale := YScale;
  ApplicationManagerInstance.UIManager.InvalidateUIObject(Self);
end;

procedure TAHMEffect.SetGamma(Gamma: TAHMColour);
begin
  FGamma := Gamma;
  ApplicationManagerInstance.UIManager.InvalidateUIObject(Self);
end;

procedure TAHMEffect.ClearProperties;
begin
  inherited;

  // Clear custom effect properties
  FXScale := DEFAULT_SCALE;
  FYScale := DEFAULT_SCALE;
  FBitmap := nil;
end;

function TAHMEffect.RenderPreview: Boolean;
{$IFDEF DESIGNER}
var
  Colour: TAHMCanvasColour;
  Control: TAHMControl;
  Dest: TAHMRectF;
{$ENDIF}
begin
{$IFDEF DESIGNER}
  with ApplicationManagerInstance, ScreenInstance, ScreenInstance.Viewport do
  begin
    Canvas.DesignerBackground(ViewportRect);

    // Render simple black and white frame to demonstrate scaling & gamma
    Dest := MakeRectF(Width / 4, Height / 4, Width / 2, Height / 2);
    if Assigned(FGamma) then Colour := FGamma.Colour else Colour := nil;
    Canvas.DesignerShape(Dest, Colour, FXScale, FYScale, False, False);

    // Render overlay bitmap with correct scaling
    if Assigned(FBitmap) then
    begin
      Control := UIManager.GetPreviewControl(TAHMControl);
      Control.Viewport := Viewport;
      Control.OwnXScale := FXScale;
      Control.OwnYScale := FYScale;
      FBitmap.Render(Control, Dest.X, Dest.Y, Dest.Width, Dest.Height);
    end;
  end;
{$ENDIF}
  Result := True;
end;

procedure TAHMEffect.Assign(Source: TPersistent);
begin
  inherited Assign(Source);

  with Source as TAHMEffect do
  begin
    Self.XScale := XScale;
    Self.YScale := YScale;
    Self.Bitmap := Bitmap;
  end;
end;

procedure TAHMEffect.SaveXMLBody(Lines: TStrings);
var
  oAncs: TAHMEffect;
  sWork: String;
begin
  // Determine which ancestor to compare against - real or empty
  oAncs := TAHMEffect(ObjectToCompare);

  // Only populate attributes that differ from our ancestor
  if ((FXScale <> DEFAULT_SCALE) and (FXScale <> oAncs.XScale)) or
     ((FYScale <> DEFAULT_SCALE) and (FYScale <> oAncs.YScale)) then
  begin
    sWork := TGB+TAG_SCALE;
    if (FXScale <> DEFAULT_SCALE) and (FXScale <> oAncs.XScale) then
      sWork := sWork + SPC+ATTR_HORIZ+ATB + Float2Str(FXScale) + ATQ;
    if (FYScale <> DEFAULT_SCALE) and (FYScale <> oAncs.YScale) then
      sWork := sWork + SPC+ATTR_VERT+ATB + Float2Str(FYScale) + ATQ;
    Lines.Add(TABS[3] + sWork + ETE);
  end;

  // Do we need to store bitmap element?
  if (FBitmap <> nil) and (FBitmap <> oAncs.Bitmap) then
    Lines.Add(TABS[3] + FBitmap.XMLReference);

  // Do we need to store gamma element?
  if (FGamma <> nil) and (FGamma <> oAncs.Gamma) then
    Lines.Add(TABS[3] + FGamma.XMLReference(TAG_GAMMA));
end;

procedure TAHMEffect.ParseFromXML(XML: TAHMXMLHelper);
var
  sName, sHoriz, sVert: String;
  EffectNode, PropsNode: TAHMXMLNode;
begin
  // Initialise parsing nodes
  EffectNode := XML.CurrentNode;
  PropsNode := nil;

  // All effect elements are optional, so lets see what we've got
  with ApplicationManagerInstance.ThemeManager do
    while XML.NextElement(EffectNode, PropsNode) do
    begin
      if XML.CurrentElement = TAG_SCALE then
      begin
        sHoriz := XML.GetAttribute(ATTR_HORIZ);
        sVert := XML.GetAttribute(ATTR_VERT);
        if sHoriz <> '' then FXScale := StrToFloatDef(sHoriz, 1.0);
        if sVert <> '' then FYScale := StrToFloatDef(sVert, 1.0);
      end
      else if XML.CurrentElement = TAG_BITMAP then
      begin
        sName := XML.GetAttribute(ATTR_NAME);
        if sName <> '' then FBitmap := VisualDescriptor.BitmapList.GetBitmap(sName);
      end
      else if XML.CurrentElement = TAG_GAMMA then
      begin
        sName := XML.GetAttribute(ATTR_NAME);
        if sName <> '' then FGamma := VisualDescriptor.ColourList.GetColour(sName);
      end;
    end;
end;

procedure TAHMEffect.InvalidateUIObject(UIObject: TAHMUIObject);
begin
  // Changes to gamma colour will invalidate the effect
  if (UIObject = Gamma) then
    ApplicationManagerInstance.UIManager.InvalidateUIObject(Self);
end;

procedure TAHMEffect.BuildProperties(Properties: TAHMUIPropertyList);
begin
{$IFDEF DESIGNER}
  inherited;

  // Build custom effect properties
  Properties.Add('Scale', 'Scale', CAT_EFFECT, HINT_SCALE);
  Properties.Add('Scale X', 'XScale', CAT_EFFECT, HINT_XSCALE);
  Properties.Add('Scale Y', 'YScale', CAT_EFFECT, HINT_YSCALE);
  Properties.Add('Bitmap', 'Bitmap', CAT_EFFECT, HINT_BITMAP);
  Properties.Add('Gamma', 'Gamma', CAT_EFFECT, HINT_GAMMA);
{$ENDIF}
end;


end.
